package com.googlecode.tidej.client.editor;

import java.util.ArrayList;

import com.google.gwt.event.dom.client.ClickEvent;
import com.google.gwt.event.dom.client.ClickHandler;
import com.google.gwt.user.client.ui.Button;
import com.google.gwt.user.client.ui.Composite;
import com.google.gwt.user.client.ui.FlexTable;
import com.google.gwt.user.client.ui.FlowPanel;
import com.google.gwt.user.client.ui.HTML;
import com.google.gwt.user.client.ui.Label;
import com.google.gwt.user.client.ui.ScrollPanel;
import com.google.gwt.user.client.ui.SuggestBox;
import com.google.gwt.user.client.ui.TextBox;
import com.googlecode.tidej.client.TidejController;
import com.googlecode.tidej.shared.model.Operation;
import com.googlecode.tidej.shared.model.Parameter;
import com.googlecode.tidej.shared.model.Property;
import com.googlecode.tidej.shared.model.Type;

public class TypeDetailWidget extends Composite {
  private static final Operation DUMMY_OPERATION = new Operation("", null);
  FlowPanel mainPanel = new FlowPanel();
  FlowPanel propertyPanel = new FlowPanel();
  ScrollPanel scrollPanel = new ScrollPanel(mainPanel);
  DocumentationEditor textArea = new DocumentationEditor();
  FlexTable propertyTable = new FlexTable();
  Label superTypeLabel = new Label();
  Button createPropertyButton = new Button("Add Property");
  private Type type;
  ArrayList<PropertyDetails> propertyDetailList = 
      new ArrayList<PropertyDetails>();
  TidejController controller;
  boolean readOnly;
  ArtifactEditor owner;
  HTML title = new HTML();
  
  public TypeDetailWidget(final ArtifactEditor artifactEditor) {
    owner = artifactEditor;
    controller = artifactEditor.controller;
    propertyTable.addStyleName("property-table");
    mainPanel.getElement().getStyle().setProperty("padding", "0 10px");
    mainPanel.add(title);
    mainPanel.add(textArea);
    textArea.setWidth("100%");
    propertyPanel.add(new HTML("<p><b>Properties</b></p>"));
    propertyPanel.add(propertyTable);
    mainPanel.add(propertyPanel);
    mainPanel.add(new Label("\u00a0"));
    mainPanel.add(createPropertyButton);
    createPropertyButton.addClickHandler(new ClickHandler() {
      @Override
      public void onClick(ClickEvent event) {
        owner.save();
        new PropertySignatureDialog(controller).createProperty(type);
      }
    });
    initWidget(scrollPanel);
  }
  
  
  public void setType(Type type) {
    this.type = type;
    readOnly = type.getLibrary().isReadOnly();

    title.setHTML(type.getName().startsWith("(") ? "<p><b>Global Documentation</b></p>" : 
        "<p><b>Class and Constructor Documentation</b></p>");
    
    textArea.setArtifactAndResize(type.getConstructor() == null ? DUMMY_OPERATION : type.getConstructor(), readOnly);
    
    propertyTable.removeAllRows();
    propertyDetailList.clear();
    createPropertyButton.setVisible(!readOnly);
    
    if (type.getOwnProperties().size() == 0) {
      propertyPanel.setVisible(false);
      return;
    }
    
    propertyPanel.setVisible(true);

    propertyTable.setHTML(0, 0, "<b>Name</b>");
    propertyTable.setHTML(0, 1, "<b>Type</b>");
    propertyTable.setHTML(0, 2, readOnly ? "\u00a0" : "<b>Initial\u00a0Value</b>");
    propertyTable.setHTML(0, 3, "<b>Documentation</b>");
    
    propertyTable.setWidth("100%");
    for (final Property p: type.getOwnProperties()) {
      propertyDetailList.add(new PropertyDetails(p));
    }
  }
  
  
  public boolean checkModifications() {
    boolean result = textArea.checkModifications();
    for (PropertyDetails details: propertyDetailList) {
      // No short-circuiting: side effects required.
      if (details.checkModifications()) {
        result = true;
      }
    }
    return result;
  }
 
  

  class PropertyDetails {
    Property property;
    DocumentationEditor documentationEditor = new DocumentationEditor();
    SuggestBox typeBox;
    TextBox initialValueBox;
    
    PropertyDetails(final Property property) {
      this.property = property;
      documentationEditor.setArtifactAndResize(property, readOnly);

      final int row = propertyTable.getRowCount();
      propertyTable.setWidget(row, 3, documentationEditor);
      
      documentationEditor.getElement().getParentElement().setAttribute("width", "80%");
      
      if (readOnly) {
        propertyTable.setHTML(row, 0, "<b>" + property.getName() + "</b>");
        propertyTable.setHTML(row, 1, property.getType().getLink());
        propertyTable.setText(row, 2, "\u00a0");
        propertyTable.addStyleName("readonly");
      } else {
        propertyTable.removeStyleName("readonly");
        Button editButton = new Button(property.getName());
        editButton.setWidth("100%");
        editButton.getElement().getStyle().setProperty("textAlign", "left");
        editButton.getElement().getStyle().setProperty("fontWeight", "bold");
        editButton.getElement().getStyle().setProperty("margin", "2px 4px 2px 0");
        editButton.addClickHandler(new ClickHandler(){
          @Override
          public void onClick(ClickEvent event) {
            new PropertySignatureDialog(controller).editProperty(property);
          }
        });
        typeBox = new SuggestBox(controller.getTypeSuggestOracle());
        if (property.getType() != null) {
          typeBox.setValue(property.getType().toString());
        }
        initialValueBox = new TextBox();
        if (property.getInitialValue() != null) {
          initialValueBox.setText(property.getInitialValue());
        }
        
        propertyTable.setWidget(row, 0, editButton);
        propertyTable.setWidget(row, 1, typeBox);
        propertyTable.setWidget(row, 2, initialValueBox);
      }
    }

    public boolean checkModifications() {
      if (readOnly) {
        return false;
      }

      boolean modified = false;
      String newTypeName = typeBox.getText();
      if (newTypeName != null && newTypeName.length() > 0) {
        Type newType = controller.getModel().getType(newTypeName);
        if (newType != null && !newType.equals(property.getType())) {
          modified = true;
          property.setType(newType);
        }
      }
      
      String newInitialValue = initialValueBox.getText();
      String oldInitialValue = property.getInitialValue();
      if (oldInitialValue == null) {
        oldInitialValue = "";
      }
      if (!oldInitialValue.equals(newInitialValue)) {
        property.setInitialValue(newInitialValue);
        modified = true;
      }
      
      if (documentationEditor.checkModifications()) {
        modified = true;
      }
      return modified;
    }
  }
}
